﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MediaGarden.Playlists.Services
{
    public class PlaylistService : IPlaylistService
    {

        private readonly Lazy<IEnumerable<IPlaylistStorageProvider>> _playlistStorageProviders;
        private readonly Lazy<IEnumerable<IPlaylistFormat>> _playlistFormats;
        private readonly Lazy<IEnumerable<IPlaylistWriter>> _playlistWriters;
        private readonly Lazy<IEnumerable<IPlaylistMapper>> _playlistMappers;
        private readonly Lazy<IEnumerable<IPlaylistOutputFilter>> _playlistOutputFilter;

        public PlaylistService(
            Lazy<IEnumerable<IPlaylistStorageProvider>> playlistStorageProviders,
            Lazy<IEnumerable<IPlaylistFormat>> playlistFormats,
            Lazy<IEnumerable<IPlaylistWriter>> playlistWriters,
            Lazy<IEnumerable<IPlaylistMapper>> playlistMappers,
            Lazy<IEnumerable<IPlaylistOutputFilter>> playlistOutputFilter
            )
        {
            _playlistStorageProviders = playlistStorageProviders;
            _playlistFormats = playlistFormats;
            _playlistWriters = playlistWriters;
            _playlistMappers = playlistMappers;
            _playlistOutputFilter = playlistOutputFilter;
        }

        public PlaylistContext BuildPlaylist(MediaGarden.Models.IMediaItem item, System.Web.Routing.RouteValueDictionary routeValues)
        {
            var context = new PlaylistContext()
            {
                MediaItem = item,
                RouteValues = routeValues,
            };

            // TODO: Could have some extra events to hook into before, during and after all of this

            // Build playlist items
            foreach (var builder in _playlistStorageProviders.Value)
            {
                builder.PlaylistLoading(context);
            }
            foreach (var builder in _playlistStorageProviders.Value)
            {
                builder.PlaylistLoaded(context);
            }
            return context;
        }

        public PlaylistContext SingleItemPlaylist(MediaGarden.Models.IMediaItem item, System.Web.Routing.RouteValueDictionary routeValues)
        {
            var context = new PlaylistContext()
            {
                // TODO: Could create a "fake" media item to act as container
                MediaItem = item,
                Items = new[]{item},
                RouteValues = routeValues,
            };

            return context;
        }

        public ActionResult MvcWritePlaylist(ControllerBase controller, PlaylistContext context)
        {
            // Find a mapper
            var mapper = _playlistMappers.Value.FirstOrDefault(m => m.FormatName == context.PlaylistFormat);
            if (mapper == null) return new HttpNotFoundResult("Unknown playlist mapper");

            var format = _playlistFormats.Value.FirstOrDefault(f => f.FormatName == context.PlaylistFormat);
            if (format == null) return new HttpNotFoundResult("Unknown playlist format");

            var writer = _playlistWriters.Value.FirstOrDefault(w => w.WriterName == format.WriterName);
            if (writer == null) return new HttpNotFoundResult("Unknown playlist output");


            mapper.CreatePlaylistModel(context);

            // Execute filters
            foreach (var filter in _playlistOutputFilter.Value)
            {
                filter.Playlist(context);
            }

            var mapped = new List<PlaylistModelItemPair>();
            foreach (var item in context.Items) {
                var pair =
                    new PlaylistModelItemPair()
                    {
                        Item = item,
                        Model = mapper.CreatePlaylistModelItem(item, context)
                    };

                // Execute filters
                foreach (var filter in _playlistOutputFilter.Value)
                {
                    filter.PlaylistItem(pair.Item, pair.Model, context);
                }

                mapped.Add(pair);
            }
            mapper.AddItemsToPlaylist(mapped, context);

            // Perform write
            return writer.WriteMvcResult(controller, context);
        }

        public string DefaultPlaylistFormat(Models.IMediaItem item)
        {
            var format = item.MediaViewer.SupportedMediaFormats().FirstOrDefault(f => _playlistFormats.Value.Any(p => p.FormatName == f));
            if (format == null) format = "";
            return format;
        }
    }
}